#ifndef _POLL_SERVER_H_
#define _POLL_SERVER_H_

#include <iostream>
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include "sock.hpp"

#define BITS 8
#define NUM (sizeof(fd_set) * BITS)
#define FD_NONE -1

using namespace std;
// 实现select读取
class PolltServer
{
public:
    static const int nfds = 100;

public:
    PolltServer(const uint16_t &port = 8080)
        : _port(port), _nfds(nfds)
    {
        _listenSock = Sock::Socket();
        Sock::Bind(_listenSock, _port);
        Sock::Listen(_listenSock);
        logMessage(DEBUG, "%s", "create base socket success");

        _fds = new struct pollfd[_nfds];
        for (int i = 0; i < _nfds; i++)
        {
            _fds[i].fd = FD_NONE;
            _fds[i].events = _fds[i].revents = 0;
        }
        _fds[0].fd = _listenSock;
        _fds[0].events = POLL_IN;

        _timeout = 1000;
    }

    void Start()
    {
        while (true)
        {
            int n = poll(_fds, _nfds, _timeout);
            switch (n)
            {
            case 0:
                logMessage(DEBUG, "%s", "time out……");
                break;
            case -1:
                logMessage(WARNING, "select error:%d  %s", errno, strerror(errno));
                break;
            default:
                HandlerEvent();
                break;
            }
        }
    }

    ~PolltServer()
    {
        if (_listenSock >= 0)
            close(_listenSock);
        if (_fds)
            delete[] _fds;
    }

private:
    void HandlerEvent() // rdfs有多个sock
    {
        for (int i = 0; i < NUM; i++)
        {
            if (_fds[i].fd == FD_NONE)
                continue; // 跳过非法fd
            // 合法fd
            if (_fds[i].revents & POLL_IN)
            {
                // 指定的fd read就绪
                if (i == 0 && _fds[i].fd == _listenSock)
                    // 读事件就绪，连接时间accept
                    Accepter();
                else
                    Recver(i);
            }
        }
    }

    void Accepter()
    {
        string clientip;
        uint16_t clientport = 0;
        // if (FD_ISSET(_listenSock, &rfds)) // 在rfds
        {
            // 获取新连接
            int sock = Sock::Accpet(_listenSock, &clientip, &clientport);
            if (sock < 0)
            {
                logMessage(WARNING, "accept error...");
                return;
            }
            logMessage(DEBUG, "get a new link success:[%s : %d] %d",
                       clientip.c_str(), clientport, sock);

            // 此时不能read和recv，因为不知道sock上面的数据什么时候来，会阻塞
            // 但select最清楚有没有数据
            // 所以得到新连接后，将新的sock交给select
            // 将sock添加到select中，只需要将fd放到数组中即可

            int pos = 1;
            for (pos = 1; pos < _nfds; pos++)
            {
                if (_fds[pos].fd == FD_NONE)
                    break;
            }
            if (pos == _nfds)
            { // 可扩容
                logMessage(WARNING, "%s ,%d ", "poll server already full ,close: %d", sock);
                close(sock);
            }
            else
            {
                _fds[pos].fd = sock;
            }
        }
    }

    void Recver(int pos)
    {
        // 读事件就绪，input事件到来，read和recv使用
        logMessage(DEBUG, "message in, get IO event: %d", _fds[pos].fd);

        // 此时select已经帮我们进行了事件检测，fd上的数据一定是就绪的，即 本次 不会被阻塞
        char buff[1024];
        int n = recv(_fds[pos].fd, buff, sizeof(buff), 0);
        if (n > 0)
        {
            buff[n] = 0;
            logMessage(DEBUG, "client [%d] : %s-", _fds[pos].fd, buff);
        }
        else if (n == 0)
        {
            logMessage(DEBUG, "client [%d] quit,me too...", _fds[pos].fd);
            // 关闭不需要的fd
            close(_fds[pos].fd);
            // 关闭当前的fd关心
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error,%d:%s", _fds[pos].fd, errno, strerror(errno));
            // 关闭不需要的fd
            close(_fds[pos].fd);
            // 关闭当前的fd关心
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
    }

    void DebugPrint()
    {
        cout << "_fds[]: ";
        for (int i = 0; i < NUM; i++)
        {
            if (_fds[i].fd == FD_NONE)
                continue;
            cout << _fds[i].fd << " ";
        }
        cout << endl;
    }

private:
    uint16_t _port;
    int _listenSock;
    struct pollfd *_fds;
    nfds_t _nfds;
    int _timeout;
};

#endif